package com.derbysoft.synxisadapter.action;

import com.derbysoft.cas.support.client.CasNavigatorService;
import com.derbysoft.cas.support.client.NavigatorItem;
import com.derbysoft.core.web.BaseAction;
import com.derbysoft.synxisadapter.commons.model.Role;
import com.derbysoft.synxisadapter.commons.model.User;
import com.derbysoft.synxisadapter.commons.repository.UserRepository;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonBeanProcessor;
import net.sf.json.processors.JsonBeanProcessorMatcher;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

@Results(value = {
        @Result(name = BaseAdapterAction.AJAX_RESULT, location = "/page/AjaxResult.ftl")
})
public class BaseAdapterAction extends BaseAction {
    private static Logger logger = LoggerFactory.getLogger(BaseAdapterAction.class);
    public static final String AJAX_RESULT = "AjaxResult";

    public static final String MESSAGE = "message";

    public static final String RESULT = "result";

    protected static final String KEY_CURRENT_USER = "CURRENT_USER";

    protected static final String MATCH_STRING = "$$_javassist_";

    @Autowired
    protected UserRepository userRepository;

    @Autowired
    protected CasNavigatorService casNavigatorService;


    private String ajaxResult;
    private static final long serialVersionUID = -9193730161406626944L;
    private static final String BUILD_NUMBER_ATTRIBUTE = "Build-Number";
    private static final String MANIFEST_MF = "/META-INF/MANIFEST.MF";
    private static final String EMPTY_BUILD_NUMBER = "DEVELOP";
    private static final String TITLE_ATTRIBUTE = "Title";
    private static final String DEFAULT_SYSTEM_TITLE = "dswitch2-synxis-adapter";

    public String getAjaxResult() {
        return ajaxResult;
    }

    protected String populateSucceededJsonResult(Object message) {
        return populateJsonResult(Boolean.TRUE, message);
    }

    protected String populateFailedJsonResult(Throwable throwable) {
        return populateJsonResult(Boolean.FALSE,
                String.format("%s: %s", throwable.getClass().getSimpleName(), throwable.getMessage()));
    }

    private String populateJsonResult(Boolean result, Object message, String... excludes) {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put(RESULT, result);
        map.put(MESSAGE, message);
        JsonConfig conf = new JsonConfig();
        conf.setExcludes(excludes);
        JSONObject jsonObject = JSONObject.fromObject(map, conf);
        ajaxResult = jsonObject.toString();
        return AJAX_RESULT;
    }

    public User getCurrentUser() {
        HttpSession session = ServletActionContext.getRequest().getSession();
        if (session.getAttribute(KEY_CURRENT_USER) != null) {
            return (User) session.getAttribute(KEY_CURRENT_USER);
        } else {
            String userName = SecurityContextHolder.getContext().getAuthentication().getName();
            if (StringUtils.isNotBlank(userName)) {
                User user = userRepository.findByName(userName);
                session.setAttribute(KEY_CURRENT_USER, user);
                return user;
            } else {
                User user = new User();
                user.setName(userName);
                user.setRoles(Arrays.asList(createRole("ANONYMOUS")));
                session.setAttribute(KEY_CURRENT_USER, user);
                return user;
            }
        }
    }

    private Role createRole(String roleName) {
        Role role = new Role();
        role.setName(roleName);
        return role;
    }

    private static class BeanProcessor implements JsonBeanProcessor {
        @Override
        public JSONObject processBean(Object bean, JsonConfig jsonConfig) {
            JSONObject jsonObject = new JSONObject();
            Field[] declaredFields = bean.getClass().getSuperclass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if (!PropertyUtils.isReadable(bean, declaredField.getName())) {
                    continue;
                }
                if (jsonConfig.getMergedExcludes().contains(declaredField.getName())) {
                    continue;
                }
                Object value = null;
                try {
                    value = PropertyUtils.getProperty(bean, declaredField.getName());
                    jsonObject.element(declaredField.getName(), value, jsonConfig);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
            return jsonObject;
        }
    }

    private static class BeanProcessorMatcher extends JsonBeanProcessorMatcher {
        @Override
        public Object getMatch(Class target, Set matches) {
            if (target.getName().contains(MATCH_STRING)) {
                return JavassistLazyInitializer.class;
            }
            return DEFAULT.getMatch(target, matches);
        }
    }

    public List<NavigatorItem> getNavigatorItems() {
        return casNavigatorService.getNavigatorItems();
    }

    public String getBuildNumber() {
        try {
            return getAttribute(BUILD_NUMBER_ATTRIBUTE);
        } catch (IOException e) {
            return EMPTY_BUILD_NUMBER;
        }
    }

    public String getSystemTitle() {
        try {
            return getAttribute(TITLE_ATTRIBUTE);
        } catch (IOException e) {
            return DEFAULT_SYSTEM_TITLE;
        }
    }

    private String getAttribute(String attribute) throws IOException {
        File manifestFile = new File(ServletActionContext.getServletContext().getRealPath(MANIFEST_MF));
        Manifest mf = new Manifest();
        mf.read(new FileInputStream(manifestFile));
        Attributes attributes = mf.getMainAttributes();
        return attributes.getValue(attribute);
    }
}

